package todomanager.View;

import java.util.*;

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

import java.awt.image.*;

/**
 * LedTimer component that can be used to show current or time elapsed
 * @author Tolga
 *
 */
public class LedTimer extends JComponent {

	private static final long serialVersionUID = 1L;

	private static final int UPDATE_INTERVAL = 100;
    
    private Calendar _now = Calendar.getInstance();
    private Calendar _startTime;    
    
    private javax.swing.Timer _timer;
    
    private int _currentWidth;
    private int _currentHeight;
    
    private boolean _showCurrentTime = false;

    
    // Digit display flags 0, 1, 2, 3, 4, 5, 6, 7, 8, 9
    private static final boolean [] leftTopUD = {true, false, false, false, true, true, true, false, true, true};  
    private static final boolean [] topUD = {true, false, true, true, false, true, true, true, true, true};
    private static final boolean [] rightTopUD = {true, true, true, true, true, false, false, true, true, true};  
    private static final boolean [] middleUD = {false, false, true, true, true, true, true, false, true, true};
    private static final boolean [] leftBottomUD = {true, false, true, false,  false, false, true, false, true, false};
    private static final boolean [] bottomUD = {true, false, true, true, false, true, true, false, true, true};   
    private static final boolean [] rightBottomUD = {true, true, false, true, true, true, true, true, true, true};
    
    /**
     * LedTimer constructor
     * @param width Width of the timer
     * @param height Height of the timer
     * @param showCurrentTime If this boolean variable set to true, the LedTimer shows the current time, otherwise it shows the time elapsed.
     */
    public LedTimer(int width, int height, boolean showCurrentTime) {
        setPreferredSize(new Dimension(width, height));
        _currentWidth = width;
        _currentHeight = height;    
        _showCurrentTime = showCurrentTime;
        
        // initialize timer that updates the time and repaints the component
        _timer = new javax.swing.Timer(UPDATE_INTERVAL, new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                updateTime();
                repaint();
            }
        });
        
        // component listener explicitly added for resizing
        this.addComponentListener(new ComponentListener() 
        {  
            public void componentHidden(ComponentEvent e) {
                }

                public void componentMoved(ComponentEvent e) {
                }

                public void componentShown(ComponentEvent e) {
                }
                
                // This method is called after the component's size changes
                public void componentResized(ComponentEvent e) {
                    Rectangle visibleRect = ((JComponent) e.getComponent()).getVisibleRect();
        			_currentWidth = (int)visibleRect.getWidth();
        			_currentHeight = (int)visibleRect.getHeight();
                }
        }
        );

    }
    
    /**
     * Stars the LedTimer
     */
    public void start() {
        _timer.start(); 
        _startTime = Calendar.getInstance();
    }
    
    /**
     * Stops the LedTimer
     */
    public void stop() {
        _timer.stop(); 
    }
    
    /**
     * Updates the current time stored inside the private variable now
     */
    private void updateTime() {
        _now.setTimeInMillis(System.currentTimeMillis());
    }
    
    /**
     * Paints the component
     */
    public void paintComponent(Graphics g) {
		long diff = (_now.getTimeInMillis() - _startTime.getTimeInMillis());
		int hourTensDigit;
		int hourDigit;
		int minuteTensDigit;
		int minuteDigit;
		int secondsTensDigit;
		int secondsDigit;
		
		// Set the LedTimer digits according to mode (current time or elapsed time?) selection
		if(_showCurrentTime){
			hourTensDigit = _now.get(Calendar.HOUR_OF_DAY) / 10;
			hourDigit = _now.get(Calendar.HOUR_OF_DAY) % 10;
			minuteTensDigit = _now.get(Calendar.MINUTE) / 10;
			minuteDigit = _now.get(Calendar.MINUTE) % 10;
			secondsTensDigit = _now.get(Calendar.SECOND) / 10;
			secondsDigit = _now.get(Calendar.SECOND) % 10;      		 
		}
		else {
			int secs = (int)(diff / 1000);
			 
			secondsTensDigit =  (secs % 60) / 10;
			secondsDigit = (secs % 60) % 10;  
			 
			int mins = secs / 60;
			minuteTensDigit = (mins % 60) / 10;
			minuteDigit = (mins % 60) % 10;
			
			int hours = mins / 60;
			hourTensDigit = (hours % 60) / 10;
			hourDigit = (hours % 60) % 10; 
		}
    	
		// Hours start at the begining of the drawing panel
    	int hoursPos = 0;
    	
    	// Define the dimensions of the building blocks of the digits
    	int ldLength = (int)(_currentWidth / 15.2);
       	int sdLength =  (int)(ldLength / 3.5);    	
    	
       	// Define the horizantalSpace parameter that is used to to set horizantal space 
       	// between graphical elements in timer
    	int horizantalSpace = (int)(ldLength * 2);
    	
    	// Draw the digits and dots on the screen
    	drawDigit(g, hourTensDigit, hoursPos, 0, sdLength, ldLength);
    	drawDigit(g, hourDigit, hoursPos + horizantalSpace, 0, sdLength, ldLength); 
    	drawDots(g, hoursPos + (int)(2.5 * horizantalSpace), 0, 2 * sdLength);
    	drawDigit(g, minuteTensDigit, hoursPos + (3 * horizantalSpace), 0, sdLength, ldLength);
    	drawDigit(g, minuteDigit, hoursPos + (4 * horizantalSpace), 0, sdLength, ldLength);   
    	drawDots(g, hoursPos + (int)(5.3 * horizantalSpace), 0, 2 * sdLength);
    	drawDigit(g, secondsTensDigit, hoursPos + (6 * horizantalSpace), 0, sdLength, ldLength);
    	drawDigit(g, secondsDigit, hoursPos + (7 * horizantalSpace), 0, sdLength, ldLength);     	
    }
    
    /**
     * Draws a digit with a given value on a given position with the given sizes
     * @param g Graphics object to draw on it
     * @param value Value to display as a digit
     * @param posX X offset of the digit to draw on graphic component
     * @param posY Y offset of the digit to draw on graphic component
     * @param unitShortEdgeLength Length of the short edge of digit building block
     * @param unitLongEdgeLength  Length of the long edge og digit building block
     */
    public void drawDigit(Graphics g, int value, int posX, int posY, int unitShortEdgeLength, int unitLongEdgeLength ) {	
    	// TODO: get this from a variable
    	g.setColor(Color.BLACK);
    	if(this.leftTopUD[value]) {
    		g.fillRect(posX + 0,posY + unitShortEdgeLength, unitShortEdgeLength, unitLongEdgeLength); // left top
    	}
    	
    	if(this.topUD[value]) {
    		g.fillRect(posX + unitShortEdgeLength, posY, unitLongEdgeLength, unitShortEdgeLength); // top
    	}
    	
    	if(this.rightTopUD[value]) {
    		g.fillRect(posX + unitShortEdgeLength + unitLongEdgeLength, posY + unitShortEdgeLength, unitShortEdgeLength, unitLongEdgeLength); // right top
    	}
    	
    	if(this.middleUD[value]) {
            g.fillRect(posX + unitShortEdgeLength, posY + unitShortEdgeLength + unitLongEdgeLength, unitLongEdgeLength, unitShortEdgeLength); // middle      		
    	}

    	if(this.leftBottomUD[value]) {
    		g.fillRect(posX + 0, posY + 2 * unitShortEdgeLength + unitLongEdgeLength, unitShortEdgeLength, unitLongEdgeLength); // left bottom
    	}
    	
    	if(this.bottomUD[value]) {
    		g.fillRect(posX + unitShortEdgeLength, posY + 2 * (unitShortEdgeLength + unitLongEdgeLength), unitLongEdgeLength, unitShortEdgeLength); // bottom
    	}
    	
    	if(this.rightBottomUD[value]) {
    		g.fillRect(posX + unitShortEdgeLength + unitLongEdgeLength, posY + 2 * unitShortEdgeLength + unitLongEdgeLength, unitShortEdgeLength, unitLongEdgeLength); // right bottom
    	}
    }
    
    /**
     * Draw the vertically aligned timer dots on the screen
     * @param g Graphics object to draw on it
     * @param posX X offset of the digit to draw on graphic component
     * @param posY Y offset of the digit to draw on graphic component
     * @param size Size of the dots
     */
    public void drawDots(Graphics g, int posX, int posY, int size) {
    	g.setColor(Color.BLACK);
		g.fillRect(posX, posY + (2 * size), size, size); 
		g.fillRect(posX, posY + (4 * size), size, size); 		
    }
    
    /**
     * Switches between elapsed time and current time
     * @param value Set this value to true to show current time, 
     * 				otherwise it will show the elapsed time starting from the moment the function is called
     */
    public void setShowCurrentTime(boolean value) {
		this.stop();
		_showCurrentTime = value;
		this.start();
    }
}
